package com.fw.system.admin.service.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.math.MathUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fw.common.IdXD;
import com.fw.constant.Constant;
import com.fw.core.text.StrFormatter;
import com.fw.enums.*;
import com.fw.system.admin.domain.*;
import com.fw.system.admin.mapper.*;
import com.fw.system.admin.service.IFwCurrencyLogService;
import com.fw.system.admin.service.IFwLogsService;
import com.fw.system.admin.service.ISysUserService;
import com.fw.utils.ChuangLanSmsUtil;
import com.fw.utils.DateUtils;
import com.fw.utils.HuaweiUtil;
import com.fw.utils.RandomUtils;
import com.fw.utils.file.FileUtils;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import com.fw.system.admin.service.IFwShopService;
import org.springframework.transaction.annotation.Transactional;

import static com.fw.enums.CommodityStatusEnum.COMMODITY_STATUS_NO;
import static com.fw.enums.ShopStatusEnum.SHOP_STATUS_FAIL;
import static com.fw.enums.ShopStatusEnum.SHOP_STATUS_PASS;

/**
 * 商铺Service业务层处理
 *
 * @author yanwei
 * @date 2021-05-10
 */
@Service
@RequiredArgsConstructor(onConstructor_={@Autowired} )
public class FwShopServiceImpl extends ServiceImpl<FwShopMapper, FwShop> implements IFwShopService
{
    private final FwShopMapper fwShopMapper;

    private final FwPolMapper polMapper;

    private final IdXD idXD;

    private final FwSpuMapper spuMapper;

    private final FwRuleDatasMapper ruleDatasMapper;

    private final FwMoneysMapper moneysMapper;

    private final IFwLogsService logsService;

    private final ISysUserService sysUserService;

    private final FwUserMapper userMapper;




    /**
     * 查询商铺
     *
     * @param id 商铺ID
     * @return 商铺
     */
    @Override
    public FwShop selectFwShopById(String id)
    {
        return fwShopMapper.selectFwShopById(id);
    }

    /**
     * 查询商铺列表
     *
     * @param fwShop 商铺
     * @return 商铺
     */
    @Override
    public List<FwShop> selectFwShopList(FwShop fwShop)
    {
        return fwShopMapper.selectFwShopList(fwShop);
    }

    /**
     * 新增商铺
     *
     * @param fwShop 商铺
     * @return 结果
     */
    @Override
    public int insertFwShop(FwShop fwShop)
    {
        fwShop.setCreateTime(DateUtils.getNowDate());
        fwShop.setId(idXD.nextId());
        return fwShopMapper.insertFwShop(fwShop);
    }

    /**
     * 修改商铺
     *
     * @param fwShop 商铺
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateFwShop(FwShop fwShop)
    {

        FwShop oldShop = getById(fwShop.getId());
        FwRuleDatas ruleDatas = ruleDatasMapper.selectById(Constant.IsRuleData.SHOP_REGIS);
        // 更改经纬度
        Assert.isTrue(ruleDatas.getRuleCount().compareTo(fwShop.getShangjia())<=0 || ruleDatas.getRuleCount().compareTo(fwShop.getOfflineShangjia()) <=0 ,String.format("当前注册商户线上线下需要质押商甲%s个起步.",ruleDatas.getRuleCount()));

        changeLatLnt(fwShop);
        // 商甲质押 - 线上
        shopShangjiaCustomer(oldShop,fwShop,Constant.ShopRuleData.SHOP_SHANGJIA_ONLINE);
        // 商甲质押 - 线下
        shopShangjiaCustomer(oldShop,fwShop,Constant.ShopRuleData.SHOP_SHANGJIA_OFFLINE);
        // 状态检测
        shopStatusAdaptation(oldShop,fwShop);
        fwShop.setUpdateTime(DateUtils.getNowDate());
        return fwShopMapper.updateFwShop(fwShop);
    }

    /**
     * 商户状态检测
     * @param oldShop newShop
     */

    @SneakyThrows
    private void shopStatusAdaptation(FwShop oldShop, FwShop newShop) {

        if (!oldShop.getStatus().equals(newShop.getStatus())) {
            // 审核通过
            // 参数拼接，密钥拼接操作.
            String id = oldShop.getId();
            newShop.setShopPay(FileUtils.shopPayQr(newShop.getShopLogo(), Constant.ShopAuthPer.SHOP_AUTH_PER.concat("shopId=".concat(id).concat("_fuwen_keys=".concat(OpenAuthEnum.SHOP_AUTH_KEYS.getBody()).concat(id)))));
            passStatus(newShop);
        }

    }

    /**
     * 处理审核通过逻辑
     * @param fwShop
     */
    private void passStatus(FwShop fwShop) {
        if (SHOP_STATUS_PASS.getCode().equals(fwShop.getStatus())) {
            // 创建管理员信息,发送后台管理地址信息,默认账号密码等.
            String shopAdminLoginPass = RandomUtils.createRandomString(6);
            FwUser fwUser = userMapper.selectById(fwShop.getUserId());
            sysUserService.sysCreateShop(fwUser, shopAdminLoginPass);
            //TODO 极光 推送给用户，默认账号 以及 & 密码
            String phone = fwUser.getPhone();
            String shopPassWord = shopAdminLoginPass;
            ChuangLanSmsUtil.sendNotice(Constant.ShopInitLogin.SHOP_LOGIN_URL,phone,shopPassWord);
           // 生成商铺 二维码。
        }
        // 审核失败需要退商甲
        if (SHOP_STATUS_FAIL.getCode().equals(fwShop.getStatus())){
            // 失败了，开始退商甲到用户钱包
            BigDecimal  back = fwShop.getOfflineShangjia().add(fwShop.getShangjia());
            FwMoneys moneys = moneysMapper.selectOne(Wrappers.<FwMoneys>lambdaQuery().eq(FwMoneys::getUserId, fwShop.getUserId()));
            moneys.setShangJia(moneys.getShangJia().add(back));
            moneysMapper.updateById(moneys);
            fwShop.setShangjia(NumberUtil.add(0D));
            fwShop.setOfflineShangjia(NumberUtil.add(0D));
            // 退回日志
            logsService.saveLogs(fwShop.getUserId(),fwShop.getUserId(), LogsTypeEnum.MONEY_INCOME, LogsModelEnum.SHANG_JIA_MODEL, StrFormatter.format("商户审核失败,一共{}商甲已经退回钱包!",back),back.toString());
        }
    }

    /**
     * 商甲 质押变更逻辑
     * @param oldShop
     * @param newShop
     */
    private void shopShangjiaCustomer(FwShop oldShop, FwShop newShop,String flag) {
        Assert.isTrue(Constant.ShopRuleData.SHOP_SHANGJIA_ONLINE.equals(flag) || Constant.ShopRuleData.SHOP_SHANGJIA_OFFLINE.equals(flag),"flag error !");
        BigDecimal oldShopShangjia = null;
        BigDecimal newShangjia = null;
        if (Constant.ShopRuleData.SHOP_SHANGJIA_ONLINE.equals(flag)){
             oldShopShangjia = Optional.of(oldShop.getShangjia()).orElse(new BigDecimal("0.000"));
             newShangjia = newShop.getShangjia();
        }else{
             oldShopShangjia = Optional.of(oldShop.getOfflineShangjia()).orElse(new BigDecimal("0.000"));
             newShangjia = newShop.getOfflineShangjia();
        }


        String userId = oldShop.getUserId();
        // 是否相等
        FwMoneys moneys = moneysMapper.selectOne(Wrappers.<FwMoneys>lambdaQuery().eq(FwMoneys::getUserId, userId));
        if (oldShopShangjia.compareTo(newShangjia) != 0){
            // 1.商甲改变了开始处理.
            // 1.1商甲是增加了还是减少了.
            if (oldShopShangjia.compareTo(newShangjia) >= 1) {
                // 减少了
                // 查看当前发布的商品量是否能够满足减少质押条件。
                Integer spuCount = spuMapper.selectCount(Wrappers.<FwSpu>lambdaQuery().eq(FwSpu::getShopId,oldShop.getId()).eq(FwSpu::getStatus,COMMODITY_STATUS_NO.getCode()));
                // 查询对应规则表
                FwRuleDatas ruleDatas = ruleDatasMapper.selectOne(Wrappers.<FwRuleDatas>lambdaQuery().eq(FwRuleDatas::getId, Constant.IsRuleData.SHOP_PUBLISH_SPU));
                BigDecimal ruleCount = ruleDatas.getRuleCount();
                // 减少的是否 满足当前商品的发布量
                BigDecimal resultPublishCount = ruleCount.multiply(new BigDecimal(spuCount));
                Assert.isTrue(newShangjia.compareTo(resultPublishCount) >=0,"不可减少商甲,需要将一些商品下架或删除!");
                // ok 开始减少，算出级差,返还到对应用户的 商甲表中.
                BigDecimal shangjiaRes = oldShopShangjia.subtract(newShangjia);
                moneys.setShangJia(moneys.getShangJia().add(shangjiaRes));
                moneysMapper.updateFwMoneys(moneys);
                logsService.saveLogs(userId,userId, LogsTypeEnum.MONEY_INCOME, LogsModelEnum.SHANG_JIA_MODEL, StrFormatter.format("商户质押商品的商甲已经减少:{},此商甲已经返回钱包中!",shangjiaRes),shangjiaRes.toString());
                //currencyLogService.saveCurrencyAsync(shangjiaRes, CurrencyLogEnum.EXPAND,userId,CurrencyLogEnum.getShangjiaType());

                return;
            }
            // 增加了
            // 1.1 算出商甲级差
            BigDecimal shangjiaRes = newShangjia.subtract(oldShopShangjia);
            // 1.2 核实用户钱包的商甲是否够。
            Assert.isTrue(moneys.getShangJia().compareTo(shangjiaRes) >=0,"商甲不足,请充值后在质押!");
            moneys.setShangJia(moneys.getShangJia().subtract(shangjiaRes));
            moneysMapper.updateFwMoneys(moneys);
            logsService.saveLogs(userId,userId, LogsTypeEnum.MONEY_CONSUMPTION, LogsModelEnum.SHANG_JIA_MODEL, StrFormatter.format("商户质押商品的商甲已经增加:{},请到后台管理发布商品!",shangjiaRes),shangjiaRes.toString());
            //currencyLogService.saveCurrencyAsync(shangjiaRes, CurrencyLogEnum.INCOME,userId,CurrencyLogEnum.getShangjiaType());

        }
    }

    /**
     * 经纬度判断
     */
    private void changeLatLnt(FwShop fwShop) {
        if (Objects.nonNull(fwShop.getLatitude()) && Objects.nonNull(fwShop.getLongitude())) {
            FwPol fwPol = polMapper.selectOne(Wrappers.<FwPol>lambdaQuery().eq(FwPol::getBusId, fwShop.getId()));
            fwPol.setLatitude(fwShop.getLatitude());
            fwPol.setLongitude(fwShop.getLongitude());
            polMapper.updateById(fwPol);

        }
    }


    /**
     * 批量删除商铺
     *
     * @param ids 需要删除的商铺ID
     * @return 结果
     */
    @Override
    public int deleteFwShopByIds(String[] ids)
    {
        Assert.isTrue(spuMapper.selectCount(Wrappers.<FwSpu>lambdaQuery().in(FwSpu::getShopId,ids)) <=0,"商铺不可删除,有未删除的商品!");
        return fwShopMapper.deleteFwShopByIds(ids);
    }

    /**
     * 删除商铺信息
     *
     * @param id 商铺ID
     * @return 结果
     */
    @Override
    public int deleteFwShopById(String id)
    {
        Assert.isTrue(spuMapper.selectCount(Wrappers.<FwSpu>lambdaQuery().eq(FwSpu::getShopId,id)) <=0,"当前商铺不可删除,有未删除的商品!");
        return fwShopMapper.deleteFwShopById(id);
    }

    /**
     * 发布商品的时候 商家是否有充裕 商甲发布
     * @param shopId 商铺编号
     * @param flag  是否线上还是线下 商品  Constant.ShopRuleData
     */
    @Override
    public void shopPublishSpu(String shopId,String flag){
        Assert.isTrue(Constant.ShopRuleData.SHOP_SHANGJIA_ONLINE.equals(flag) || Constant.ShopRuleData.SHOP_SHANGJIA_OFFLINE.equals(flag),"flag error !");
        FwShop oldShop = selectFwShopById(shopId);
        BigDecimal oldShopShangjia = null;
        String roleData = Constant.IsRuleData.SHOP_PUBLISH_SPU;
        String spuIsOffline = SpuEnum.SPU_ON.getCode();
        if (Constant.ShopRuleData.SHOP_SHANGJIA_ONLINE.equals(flag)){
            // 线上商甲质押
            oldShopShangjia = Optional.of(oldShop.getShangjia()).orElse(new BigDecimal("0.000"));
        }else{
            // 线下商甲质押
            oldShopShangjia = Optional.of(oldShop.getOfflineShangjia()).orElse(new BigDecimal("0.000"));
            spuIsOffline = SpuEnum.SPU_OFF.getCode();
            roleData = Constant.IsRuleData.SHOP_OFF_PUBLISH_SPU;
        }
        // 查看当前发布的商品量是否能够满足减少质押条件, 分为线上，还是线下
        Integer spuCount = spuMapper.selectCount(Wrappers.<FwSpu>lambdaQuery().eq(FwSpu::getShopId,oldShop.getId()).eq(FwSpu::getStatus,COMMODITY_STATUS_NO.getCode()).eq(FwSpu::getIsOffline,spuIsOffline));
        // 查询对应规则表
        FwRuleDatas ruleDatas = ruleDatasMapper.selectOne(Wrappers.<FwRuleDatas>lambdaQuery().eq(FwRuleDatas::getId, roleData));
        BigDecimal ruleCount = ruleDatas.getRuleCount();
        // 减少的是否 满足当前商品的发布量 现有商甲 * 规则数 = 可发布的商品量
        BigDecimal maxSpuCount = oldShopShangjia.multiply(ruleCount);
        Assert.isTrue(maxSpuCount.compareTo(NumberUtil.add(spuCount)) >=0,"商甲不足,请到用户端抢购商甲!");
    }

}
